/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
 *
 */

import { FileSet } from '@ohos/hvigor';
import { TaskInputValue } from '@ohos/hvigor';
import * as fse from 'fs-extra';
import path from 'path';

import { BuildArtifactConst } from '../../const/build-directory-const.js';
import { ApiVersion } from '../../const/sdk-const.js';
import { AbilityTypeEnum } from '../../enum/ability-type-enum.js';
import { CompileModeEnum } from '../../enum/compile-mode-enum.js';
import { LegacyAbilityModel } from '../../model/ability/legacy-ability-model.js';
import { LegacyModuleModelImpl } from '../../model/module/legacy-module-model-impl.js';
import { InjectUtil } from '../../utils/inject-util.js';
import { AbstractGenerateLoaderJson } from '../abstract-generate-loader-json.js';
import { TaskNames } from '../common/task-names.js';
import { ModuleTargetData } from '../data/hap-task-target-data.js';
import { TargetTaskService } from '../service/target-task-service.js';

import { LegacyGenerateJsManifest } from './legacy-generate-js-manifest.js';
import { LegacyPreBuild } from './legacy-pre-build.js';

/**
 * 生成fa模型编译需要的loader.json
 */
export class LegacyGenerateLoaderJson extends AbstractGenerateLoaderJson {
  private readonly outputAceLoaderJsonArray: string[] = [];
  private readonly multiResourceBuildArray: (object | undefined)[] = [];
  private readonly isWorkerArray: boolean[] = [];

  declareInputs(): Map<string, TaskInputValue> {
    return super.declareInputs().set('multiResourceBuildArray', JSON.stringify(this.multiResourceBuildArray));
  }

  declareOutputFiles(): FileSet {
    return new FileSet().addEntries([...this.outputAceLoaderJsonArray]);
  }

  initTaskDepends() {
    this.declareDepends(LegacyPreBuild.name);
    this.declareDepends(LegacyGenerateJsManifest.name);
  }

  constructor(taskService: TargetTaskService) {
    super(taskService, TaskNames.LegacyFATask.GENERATE_LOADER_JSON);
    const moduleModel: LegacyModuleModelImpl = this.service.getModuleModel()! as LegacyModuleModelImpl;
    const abilityObjs: LegacyAbilityModel[] = moduleModel.getLegacyAbilities(this.targetName);

    for (let i = 0; i < abilityObjs.length; i++) {
      const abilityInfo: LegacyAbilityModel = abilityObjs[i];
      const abilityType = abilityInfo.getType();
      if (abilityType === AbilityTypeEnum.PAGE || abilityType === AbilityTypeEnum.FORM || abilityType === AbilityTypeEnum.WORKER
        || abilityType === AbilityTypeEnum.DATA || abilityType === AbilityTypeEnum.SERVICE) {
        const aceLoaderJson = path.resolve(
          taskService.getTargetData().getPathInfo().getIntermediatesLoaderPath(),
          abilityInfo.getRelateSrcPath(),
          BuildArtifactConst.LOADER_JSON,
        );
        this.outputAceLoaderJsonArray.push(aceLoaderJson);
        this.isWorkerArray.push(abilityType === AbilityTypeEnum.WORKER);
      }
    }
  }

  private shouldLoaderWorker(index: number) {
    if (InjectUtil.isPreviewProcess()) {
      return true;
    }
    if (
      this.compileApiVersion > ApiVersion.API_VERSION_8 &&
      this.workerConfig &&
      this.workerConfig.filter((workerFile) => path.extname(workerFile) === '.ts').length > 0
    ) {
      return this.isWorkerArray[index];
    }
    return index === 0;
  }

  protected doTaskAction(): void {
    const moduleModel: LegacyModuleModelImpl = this.service.getModuleModel()! as LegacyModuleModelImpl;
    const abilityObjs: LegacyAbilityModel[] = moduleModel.getLegacyAbilities(this.targetName);
    for (let i = 0; i < abilityObjs.length; i++) {
      const abilityInfo: LegacyAbilityModel = abilityObjs[i];
      this.multiResourceBuildArray.push(this.getMultiResourceBuild(this.targetService.getTargetData(), abilityInfo));
    }

    for (let i = 0; i < this.outputAceLoaderJsonArray.length; i++) {
      const loaderObj: object = {
        workers: this.shouldLoaderWorker(i) ? this.workerConfig : undefined,
        multiResourceBuild: this.multiResourceBuildArray[i],
        modulePathMap: this.modulePathMap,
        compileMode: CompileModeEnum.JS_BUNDLE, // fa模型固定为jsBundle
        projectRootPath: this.projectRootPath,
        packageManagerType: this.isOhpmProject ? 'ohpm' : 'npm',
      };
      fse.outputJSONSync(this.outputAceLoaderJsonArray[i], loaderObj);
    }
  }

  private getMultiResourceBuild(targetData: ModuleTargetData, abilityObj: LegacyAbilityModel): object | undefined {
    const targetConfigOpt = targetData.findTargetConfigOpt(abilityObj);
    if (targetConfigOpt) {
      if (!targetConfigOpt.pages) {
        return {
          pages: this.getManifestPage(targetData, abilityObj),
          res: targetConfigOpt.res,
        };
      }
      return {
        pages: targetConfigOpt.pages,
        res: targetConfigOpt.res,
      };
    }
    return undefined;
  }

  /**
   * loader.json中的pages与manifest.json中的pages保持一致
   * loader.json: build/{default}/intermediates/loader/{default}/{MainAbility}/loader.json
   * manifest.json: build/{default}/intermediates/manifest/{default}/{MainAbility}/manifest.json
   *
   * @param targetData targetData
   * @param abilityInfo current page ability info
   * @private
   */
  private getManifestPage(targetData: ModuleTargetData, abilityInfo: LegacyAbilityModel): string[] | undefined {
    const manifestPath = path.resolve(
      this.pathInfo.getIntermediatesLegacyManifestJson(),
      abilityInfo.getRelateSrcPath(),
      BuildArtifactConst.LEGACY_MANIFEST_JSON,
    );
    if (fse.existsSync(manifestPath)) {
      return [];
    }
    const manifestJsonObj = fse.readJSONSync(manifestPath);
    return manifestJsonObj.pages;
  }
}
